package net.tngou.tpage.action;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.FileBasedBuilderParametersImpl;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.configuration2.io.FileLocatorUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import net.tngou.tpage.entity.Ask;
import net.tngou.tpage.enums.CookieEnum;
import net.tngou.tpage.enums.LevelEnum;
import net.tngou.tpage.http.HttpRequest;
import net.tngou.tpage.http.HttpResponse;
import net.tngou.tpage.http.HttpSession;
import net.tngou.tpage.http.SessionContext;
import net.tngou.tpage.jdbc.DBManager;
import net.tngou.tpage.jdbc.PageUtil;
import net.tngou.tpage.pojo.POJO;
import net.tngou.tpage.pojo.User;
import net.tngou.tpage.service.BaseService;
import net.tngou.tpage.util.Base64Coder;
import net.tngou.tpage.util.BeanUtil;
import net.tngou.tpage.util.ConfigUtil;
import net.tngou.tpage.util.Freemarker;
import net.tngou.tpage.util.IPv4Util;
import net.tngou.tpage.util.StringUtil;



/**
 * 所有的action类的父类
 * @author 陈磊
 *
 */
public  abstract class BaseAction  
{

	private static final Logger log= LoggerFactory.getLogger(BaseAction.class);
	@SuppressWarnings("rawtypes")
	private static Class[] NO_ARGS_CLASS = new Class[0];
	private static Object[] NO_ARGS_OBJECT = new Object[0];
	protected HttpRequest request;
	protected HttpResponse response;
	protected ServletContext context;
	protected HttpSession session;
	protected Configuration cfg; 
	protected Map<String, Object> root = new HashMap<String, Object>();
	protected String tngou_id=null;
	protected static final String Prefix=POJO.DABASE+"_";
	protected BaseService service = new BaseService();
	protected final static int SIZE=20;
	protected Ask ask;
	protected User user;
	/**
	 * 初始化
	 * @param request
	 * @param response
	 * @throws ConfigurationException 
	 */
	public void init(HttpRequest request, HttpResponse response)  {
		this.request = request;
		this.response = response;
		this.context = request.getServletContext(); //3.0
		this.session = new SessionContext();
		//接受处理
		this.ask=getAsk(Ask.class);	
		String[] params = request.getParams();
		if(ask.getId()==0&&params!=null&&NumberUtils.isNumber(params[0]))//把第一个参数复制给ID
		{	
			ask.setId(Integer.parseInt(params[0]));					
		}
		if(StringUtil.isNotEmpty(ask.getUrl()))
		{
			ask.setUrl(Base64Coder.decodeUrlBase64Safe(ask.getUrl()));
		}
		this.tngou_id=_GetCookieID(request);
		this.user=getUser();
		cfg = new Configuration(Configuration.getVersion());
		 
		try {
		
		    //加载并设置freemarker.properties  
			FileBasedBuilderParametersImpl builder =
				    new FileBasedBuilderParametersImpl()
				        .setFileName("freemarker.properties");
	      FileHandler header = builder.getFileHandler();
	      InputStream inputStream = new FileInputStream(FileLocatorUtils.fileFromURL(header.getURL()));
		  cfg.setSettings(inputStream);
		   
			
		     
			
		} catch (  IOException | TemplateException e) {
			
			log.error("读取配置文件freemarker.properties错误！");
			e.printStackTrace();
		}
	
		cfg.setServletContextForTemplateLoading(
				context, "WEB-INF/templates");
		cfg.setDefaultEncoding("UTF-8");
		
		
	}
	
	/**
	 * 执行的类
	 * @throws ServletException
	 * @throws IOException
	 */
	public  void run() 
	{
			String action = request.getAction();
		
			//aop调用 执行 action 方法
					try {
						this.getClass().getMethod(action, NO_ARGS_CLASS).invoke(this, NO_ARGS_OBJECT);
					} catch (Exception e) {
						log.error("{} 类中 没有实现 {}方法 \n" + e,this.getClass(),action);
						run_404();//返回500
						e.printStackTrace();
					}finally
					{
						DBManager.closeConnection();//关闭数据库连接
					}
				

	};
	
	public  void run(String action) 
	{
			//String action = request.getAction();
		
			//aop调用 执行 action 方法
					try {
						this.getClass().getMethod(action, NO_ARGS_CLASS).invoke(this, NO_ARGS_OBJECT);
					} catch (Exception e) {
						log.error("{} 类中 没有实现 {}方法 \n" + e,this.getClass(),action);
						run_404();//返回500
						e.printStackTrace();
					}finally
					{
						DBManager.closeConnection();//关闭数据库连接
					}
				

	};
	
	protected void destroy()
	{
		
	}
	
	/**
	 * 默认执行的方法
	 * @throws ServletException
	 * @throws IOException
	 */
	public void execute() throws ServletException, IOException 
	{
		log.error("{} 类中 没有继承 execute() 方法 \n" ,this.getClass());
		

	}
	
	/**
	 * 跳转后浏览器地址栏变化<br>
	 * <p>
	 * 传值出去的话，只能在url中带parameter或者放在session中，无法使用request.setAttribute来传递。<br> 
	 * @param url 重定向访问的路径  http://127.0.0.1:8080/ape/index.html
	 */
	protected void sendRedirect(String url)
	{
		try {
		
			response.sendRedirect(url);	
		} catch (IOException e) {
			log.error("访问的URL{}不存在！\n"+e,url);
			run_404();
			e.printStackTrace();
		}
		return;
	}
	
	/**
	 * 301、302  都表示重定向， 区别是 301 是永久性重定向，302 是临时性重定向。
	 * 301
		SC_MOVED_PERMANENTLY
		页面已经永久移到另外一个新地址
		302
		SC_MOVED_TEMPORARILY
		页面暂时移动到另外一个新的地址
	 * @param url
	 * @param status
	 */
	protected void sendRedirect(String url,int status)
	{

			response.addHeader("location", url);
			response.setStatus(status);
							
		return;
	}
	
	/**
	 * Servlet页面跳转的路径是相对路径。forward方式只能跳转到本web应用中的页面上。
	 *<br>
	 *	跳转后浏览器地址栏不会变化。
	 *<br>
	 *使用这种方式跳转，传值可以使用三种方法：url中带parameter，session，request.setAttribute
	 *
	 * @param uri 跳转的相对路径 如：input.jsp
	 */
	public void forward(String uri) {
		
		
			try {
				request.getRequestDispatcher(uri).forward(request, response);
			} catch (ServletException | IOException e) {
				run_500();//返回500
				e.printStackTrace();
			} 
			
		
		return;
	}
	
	
	/**
	 * text/html 格式的返回
	 * @param html 显示的html
	 */
	protected void printHtml(String html) 
	{
		try {
			response.setContentType("text/html; charset=UTF-8");
			response.getWriter().print(html);
		} catch (IOException e) {
			log.error("显示text/html{}报错\n"+e,html);
			run_500();//返回500
			e.printStackTrace();
			
		}
		return;
	}
	
	/**
	 * application/json 格式的返回json
	 * @param json 返回的json
	 */
	protected void printJson(String json) {
		try {
			response.setContentType("application/json; charset=UTF-8");
			response.getWriter().print(json);
		} catch (IOException e) {
			log.error("返回application/json{}报错\n"+e,json);
			run_500();//返回500
			e.printStackTrace();
		}
		return;
	}
	
	/**
	 *    通过Freemarker方式显示
	 * @param ftl ftl文件
	 * @param root 数据
	 */
 protected void printFreemarker(String ftl,Map<String,Object> root)
  {
	 
	//HttpSession session = new SessionContext( request);

	 //设置默认信息
	 if(root.get("title")==null)  root.put("title", ststeminfo().get("name"));
	 if(root.get("keywords")==null)  root.put("keywords", "");
	 if(root.get("description")==null)  root.put("description", "");
	 if(root.get("ask")==null)  root.put("ask", ask);
	 root.put("Domain", getDomain());
	 root.put("versioncode", ststeminfo().get("versioncode"));
	 root.put("ImgUrl", getDomain().substring(0, getDomain().length()-1));//图片地址
	 root.put("info", ststeminfo());//系统信息
	 root.put("freemarker",new Freemarker());
	 if(root.get("user")==null) root.put("user", getUser());
	 if(root.get("active")==null) root.put("active", request.getModule());
	 if(root.get("active")==null) root.put("active", "index");
	 if(root.get("action")==null) root.put("action", request.getAction());
	 if(root.get("action")==null) root.put("action", "execute");
	 if(root.get("url")==null)  {
		 String url = request.getRequestURI().replaceFirst("/", "");
		 if(url.startsWith(POJO.DABASE+"/"))url= url.replaceFirst(POJO.DABASE+"/", "");
          url=getDomain()+url; 
          if(ask.getPage()!=1||ask.getRows()!=new Ask().getRows()||StringUtil.isNotEmpty(ask.getKeyword()))//处理分页和搜索的URL
          {
        	  url= url+"?page="+ask.getPage()+"&size="+ask.getRows();
        	  if(StringUtil.isNotEmpty(ask.getKeyword()))url= url+"&keyword="+ask.getKeyword();
          }
          url= Base64Coder.encodeBase64Safe(url);
		 root.put("url", url); 
	 }else
	 {
		 String url=root.get("url").toString();
		 url= Base64Coder.encodeBase64Safe(url);
		 root.put("url", url); 
	 }

	 try {
		Template  t = cfg.getTemplate(ftl);
		t.setEncoding("UTF-8");
		response.setContentType("text/html; charset=" + t.getEncoding());
		Writer out = response.getWriter();
		t.process(root, out);
	
	} catch (IOException | TemplateException  e) {
		log.error("通过Freemarker文件{}错误",ftl);
		run_500();//返回500
		e.printStackTrace();

	}
      
  }
 
 
	
	
	public String toJsonP(POJO pojo)
	{
		JSONObject jsonObject = (JSONObject) JSONObject.toJSON(pojo);
		jsonObject.put("status", true);	
		return toJsonP(ask.getCallback(), jsonObject.toJSONString());
	}
	public String toJsonP( JSONObject jsonObject)
	{
		jsonObject.put("status", true);	
		return toJsonP(ask.getCallback(), jsonObject.toJSONString());
	}
	
	public String toJsonP(JSONArray array) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("rows", array);
		return toJsonP(jsonObject);
	}
	public String toJsonP(List<?> list) {
		if(list==null) list = new ArrayList<>();
		JSONArray array=(JSONArray) JSON.toJSON(list);
		return toJsonP(array);
	}
	
	public String toJsonP(String callback,String json,int total)
	{
		if(callback==null)
		{
			json="{ \"status\":"+true+",\"total\":"+total+",\"rows\":"+json+"}";
		}else
		{
			json=callback+"({ \"status\":"+true+",\"total\":"+total+", \"rows\":"+json+"})";
		}
		return json;
	}
	

	/**
	 *  把Page转为JSON 数据
	 * @param page
	 * @return
	 */
	public String toJsonPage(PageUtil page) {
		String callback =ask.getCallback();
	
		List<?> list =  page.getList();	 	
		 String json=JSON.toJSONString(list);
		return toJsonP(callback, json, page.getTotal());	
	}
 
 
 /**
  * 500页面
  */
	 public void run_500() {
		 try {
			response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
			response.setCharacterEncoding("UTF-8");
		} catch (IOException e) {
			
			e.printStackTrace();
		}//返回500
	}
 
	 /**
	  * 404页面
	  */
	 public void run_404() {
		 try {
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
			response.setCharacterEncoding("UTF-8");
		} catch (IOException e) {
			
			e.printStackTrace();
		}
	}
	 
	 /**
	  * 403页面
	  */
	 public void run_403() {
			
		 try {
			response.sendError(HttpServletResponse.SC_FORBIDDEN );
			response.setCharacterEncoding("UTF-8");
		} catch (IOException e) {
		
			e.printStackTrace();
		}
	 }


	 
	 protected <T> T getAsk( Class<T> beanClass)
		{
			Map<String, ? extends Object> map = request.getParameterMap();	
			T t = null;
			try {
				t = beanClass.newInstance();
				BeanUtil.populate(t, map);
			} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
			
				e.printStackTrace();
			}
	
			return t;
		}
	 
	 
	 public void run_false(String message) {
			
			JSONObject obj = new JSONObject();
			obj.put("status", false);
			obj.put("msg", message);
			obj.put("code", 404);
			
			printJson(this.toJsonP(this.ask.getCallback(), obj.toString()));

		}
		 
	public void run_success(String message) {
					JSONObject obj = new JSONObject();
					obj.put("status", true);
					obj.put("msg", message);
					printJson(this.toJsonP(this.ask.getCallback(), obj.toString()));
		}
	public void run_success(String message,long id) {
		JSONObject obj = new JSONObject();
		obj.put("status", true);
		obj.put("msg", message);
		obj.put("id", id);
		printJson(this.toJsonP(this.ask.getCallback(), obj.toString()));
}	
	public void run_nologin() {

			 JSONObject obj = new JSONObject();
				obj.put("status", false);
				obj.put("msg", "需要用户认证");
				obj.put("code", 500);
			printJson(this.toJsonP(ask.getCallback(), obj.toJSONString()));
		}
	
	/**
	 * 这里返回的数据主要有JSonp了Json两种处理方式
	 */
	public String toJsonP(String callback,String json)
	{
		if(callback!=null)
		{
			json=callback+"("+json+")";
		}
		return json;
	}
	 
	 protected String getDomain()
	 {
		 return ststeminfo().get("domain");
		
	 }
	
	 public String _GetCookieID( HttpRequest request) {
		 
		 //兼容API接口参数传递
		 String ercloud_id= request.getParameter("access_token");
		 if(ercloud_id!=null) return ercloud_id;
		 Cookie[] cookies = request.getCookies();//这样便可以获取一个cookie数组		 
		 if(cookies==null)
			 return null;
		 
		 for(Cookie cookie : cookies){
			 if(cookie.getName().equals(CookieEnum.access_token.toString()))
			 {
				 ercloud_id=cookie.getValue();
				 if(StringUtil.isNoneBlank(ercloud_id)&&session.getUser(ercloud_id)==null)
				{
						response.removeAutoLoginCookie(); //移除登录Cook；
						return null;
				}
				 return ercloud_id;
			 }
		   
		 }
		return null;
	}
	 
	 protected Map<String ,String> ststeminfo() {
		
		PropertiesConfiguration properties =ConfigUtil.GetConfig("info.properties");
		if(properties==null)return new HashMap<>();
		Map<String, String> cp_props =new HashMap<String, String>();//使用cp_props做临时的配置文件的存储
		Iterator<String> iterable = properties.getKeys();//取得配置文件中的key
		while (iterable.hasNext()) {
			String skey=iterable.next();
			cp_props.put(skey, properties.getString(skey));				
		}
		return cp_props;	
			
	}
	 
	
	 /**
	  * 取得验证码的code
	  * @return
	  */
	protected String _GetCookieCaptacha( ) {
			 Cookie[] cookies = request.getCookies();//这样便可以获取一个cookie数组

			 
			 if(cookies==null)
				 return null;
			 
			 for(Cookie cookie : cookies){
				 if(cookie.getName().equals(CookieEnum.tngou_captacha.toString()))
				 {
					 return cookie.getValue();
				 }
			   
			 }
			return null;
		}
	
	
	/**
	 * 判断参数是否为空！
	 * @param args
	 * @return
	 */
	protected boolean isEmpty(Object ...args)
	{

		for (Object string : args) {
			if(string==null)return true;
			if(StringUtils.isEmpty(string.toString())) return true;
		}
		return false;
		
	}
	
	 protected User getUser() {
		 User user= session.getUser(tngou_id);
		 if(user==null) response.removeAutoLoginCookie();
		 return user;
	}
	 protected void setUser(User user) {
			session.setUser(user);
	}
	 protected void removeUser() {
			session.deleteUser(tngou_id);
	}
	 /**
		 * 是否是微信客户端
		 * @return
		 */
		protected boolean isWeixin() {
			String agent = request.getHeader("User-Agent"); 
			return agent.indexOf("MicroMessenger")>-1?true:false;
			
		}
		
		/**
		 * 跳转到登录界面
		 */
		protected void sendLogin() {
			 String url = request.getRequestURI().replaceFirst("/", "");
			 if(url.startsWith(POJO.DABASE+"/"))url= url.replaceFirst(POJO.DABASE+"/", "");
	          url=getDomain()+url; 
			sendRedirect(getDomain()+"login?url="+url);
		}
	
	
		
		
		
}
